'''
Runing this script should output all of the raw information for experiment 1
as defined in the assignment specification doc.
players compared should be defined each in a faile named
 'BlokusAgent<choose the name>.py'.
Output should be to file
 'output1.txt' (or csv).
Alternatively, you may split the output into multiple files named
'output1_<a relevant name>.txt' (or csv).
'''
from BlokusGameAgentExample import BlokusGameAgentExample
import BlokusGameConstants as C
from BlokusGameState import BlokusGameState
from GameRunner import GameRunner
from BlokusCompetitionAgent import BlokusCompetitionAgent
from itertools import product
from collections import Counter
out = 'output1.txt'
# (or csv)

# out_<...> = 'output1_<a relevant name>.txt' (or csv)

from draw import GameBoard


def get_pieces(self):
    index = self.boardSizeWithBorder
    for row in range(self.boardSize):
        index += 1
        for col in xrange(0, self.boardSize):
            mask = 1 << index
            for color in self.currentPlayer.colors:
                if mask & color.boardBinary:
                    yield row, col, color.color, self.currentPlayer
                    break
            else:
                for color in self.opponentPlayer.colors:
                    if mask & color.boardBinary:
                        yield row, col, color.color, self.opponentPlayer
                        break
                else:
                    yield row, col, 'white', None
            index += 1
        index += 1


def draw(self, action):
    b = GameBoard()
    for tup in get_pieces(self):
        b.placepiece(*tup)
    b.write("{} - {}\n({})".format(self.currentPlayer,
                                   self.currentPlayer.getCurrentColor(),
                                   action))
    # b.draw()
    b.mainloop()

BlokusGameState.draw = draw


def get_simple_with_depth(d):
    p = BlokusGameAgentExample()
    p.fixedDepth = d
    return p


players = {
    'simple2': get_simple_with_depth(2),
    'simple4': get_simple_with_depth(4),
    # 'simple6': get_simple_with_depth(6),
    }


# results:
# simple4 vs. simple2 Counter({'FIRST': 6, 'SECOND': 4})
# simple2 vs. simple4 Counter({'SECOND': 6, 'FIRST': 3, 'TIE': 1})


def run(first, second, timeLimit=C.NO_LIMIT):
    boardSize, orderedShapesMode, _ = C.GameOption[2]
    agents = {C.Players.FIRST: first, C.Players.SECOND: second}
    state = BlokusGameState().setup(boardSize, 'shapes.txt', orderedShapesMode)
    finalState = GameRunner(state, agents, timeLimit).run()
    # print finalState
    # finalState.draw(None)
    res = finalState.getWinner()
    try:
        name = "Winner: ", res, agents[res].name if hasattr(agents[res], 'name') else 'example'
    except KeyError:
        name = "TIE"
    print name
    return res, name


def match(a, depth=2):
    p1 = BlokusCompetitionAgent(depth, a)
    p2 = get_simple_with_depth(depth)

    def do(r1, r2):
        res, _ = run(r1, r2)
        print '.',
        if res == 'TIE':
            return 0.5
        if res == 'FIRST':
            return r1 == p1
        return r1 == p2
    res = do(p1, p2) + do(p2, p1)
    print res,
    return res


def run10(first, second, timeLimit=C.NO_LIMIT, times=10):
    return Counter(run(first, second, timeLimit)[0] for _ in range(times))

import cProfile
import pstats
profiler = cProfile.Profile()


def experiment(out=out, times=10, timeLimit=C.NO_LIMIT, **players):
    t = players.items()
    for (n1, p1), (n2, p2) in product(t, t):
        if n1 != n2:
            print n1, 'vs.', n2
            if not hasattr(p1, 'name'):
                p1.name = n1 + '(depth={})'.format(p1.fixedDepth)
            if not hasattr(p2, 'name'):
                p2.name = n2 + '(depth={})'.format(p2.fixedDepth)
            counter = run10(p1, p2, times=times, timeLimit=timeLimit)
            with open(out, 'a') as outfile:
                outfile.write(p1.name + ' vs. ' + p2.name + ' ')
                outfile.write(str(counter))
                outfile.write('\n')
            print counter


def go(a=1000):
    return experiment(example2=get_simple_with_depth(2),
                      our2=BlokusCompetitionAgent(2, a),
                      #example4=get_simple_with_depth(4),
                      #our4=BlokusCompetitionAgent(4, a),
                      )


if __name__ == '__main__':
    if False:
        try:
            profiler.runcall(go)
        finally:
            stats = pstats.Stats(profiler)
            stats.sort_stats("time")
            stats.print_stats()
    else:
        go(1000)
    # experiment(**players)
    # run experiment 1
    # output raw data to out file(s)

    # after running, manually rename the output file(s) by adding '_results'
    # before the file extension.
    # for example: output1_results.txt
